//
//	A View that implements Dragging in 3.0
//	Greg Burd
//		Copyright NeXT Computer, Inc 1992 All Rights Reserved
//
//	Created 7-4-92 -- (Improved from existing code by Randy Nelson)
//
//	You may freely copy, distribute and reuse the code in this example.
//	NeXT disclaims any warranty of any kind, expressed or implied, as to
//	its fitness for any particular use.
//

#import "DragView.h"
#import "Text_Console.h"		// text category that allows formated printf:
#import <appkit/Application.h>
#import <appkit/Pasteboard.h>
#import <appkit/OpenPanel.h>
#import <appkit/graphics.h>		// for NXFrameRectWithWidth

@implementation DragView

/*-------------------- methods to get things set up */

- initFrame:(const NXRect *)theFrame
{
	const char *const types[] = {NXPostScriptPboardType};
	
    [textObj printf:"In initFrame:\n"];
    [super initFrame:theFrame];
	
	//register which pasteboard types you will accept
    [self registerForDraggedTypes:(const char *const*)&types count:1];
	drawBackground = YES;
	
    return self;
}

- awakeFromNib
{
    [textObj printf:"In awakeFromNib:\n"];
	
	framed = NO;
    [window makeKeyAndOrderFront:self];
    return self;
}

/*-------------------- methods to be the source of a dragging operation */

- mouseDown:(NXEvent *)theEvent
{
    NXPoint 	zero = {0.0, 0.0};
    id 			thePboard;

    [textObj printf:"In mouseDown:\n"];
	
	// Prevent default window ordering (this is a new appkit feature)
    [NXApp preventWindowOrdering];

    //get the Pboard
    thePboard = [Pasteboard newName:NXDragPboard];
    [thePboard declareTypes:&NXPostScriptPboardType num:1 owner:self];
    
    //put an EPS of the image on the Pboard
	drawBackground = NO;
	[self writePSCodeInside:&bounds to:thePboard];
	drawBackground = YES;
    
    //start the drag
    [self dragImage:theImage	// visable on screen during drag
		at:&zero				// offset the mouse point for the drag
		offset:&zero			// offset the inital mouse pt
		event:theEvent			// theEvent structure
		pasteboard:thePboard	// a Pasteboard with data on it
		source:self				// source object
		slideBack:YES];			// if no destination animate back to source
	
    return self;
}

- draggedImage:(NXImage *)image beganAt:(NXPoint *)screenPoint
{
    [textObj printf:"In draggedImage::\n"];
	return self;
}

- (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
{
    [textObj printf:"In draggingSourceOperationMaskForLocal:\n"];
	
    return (NX_DragOperationCopy | NX_DragOperationGeneric);
}

- draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint deposited:(BOOL)flag
{
    [textObj printf:"In draggedImage:\n"];
	
    return self;
}

/*-------------------- methods to be the destination of a dragging operation */

- (NXDragOperation)draggingEntered:sender
{
    [textObj printf:"In draggingEntered:\n"];

	// check to make sure we are not the source and this operation is a copy
    if (([sender draggingSourceOperationMask] & NX_DragOperationCopy) &&
							([sender draggingSource] != self)) {
		framed = YES;
		[self display];
		//return the type of operation we want to do, this will dictate
		//the type of cursor will show up when accepting the drag
		return NX_DragOperationCopy;
    }
	return NX_DragOperationNone;
}

- (NXDragOperation)draggingUpdated:sender
{
    [textObj printf:"In draggingUpdated:\n"];
	
	// make sure that this is a copy operation, and that this instance
	// of DragView is not the source
    if (([sender draggingSourceOperationMask] & NX_DragOperationCopy) &&
									([sender draggingSource] != self)) {
		framed = YES;
		[self display];
		return NX_DragOperationCopy;
    }
	return NX_DragOperationNone;
}

- draggingExited:sender
{
    [textObj printf:"In draggingExited:\n"];
	if (framed) {
		framed = NO;
		[self display];
	}
    return self;
}

- (BOOL)prepareForDragOperation:sender
{
    [textObj printf:"In performDragOperation:\n"];
	
    return YES;
}

- (BOOL)performDragOperation:sender
{
    [textObj printf:"In performDragOperation:\n"];
	
	// make sure that what we are getting is from the same application
	// and did not originate from this view.
    if ([sender isDraggingSourceLocal] && ([sender draggingSource] != self)) {
		
		// if I had an image free it
		if (theImage) [theImage free];
	
		// new call in NXImage allows you to initFromPasteboard
		theImage = [[NXImage alloc] initFromPasteboard:
										[sender draggingPasteboard]];
		
		[theImage setDataRetained:YES];	// otherwise it scales poorly
		[theImage setScalable:YES];		// scaleable yes
		[theImage setSize:&bounds.size];// rescale to the same size as view
		framed = NO;
    	[self display];
	}
	if(framed) {
		framed = NO;
    	[self display];
	}
    return YES;
}

- concludeDragOperation:sender
{
    [textObj printf:"In concludeDragOperation:\n"];
	// This is within a oneway call, so you can send a call to Workspace
	// without it getting 'hung up' waiting for a return

    return self;
}

/*-------------------- methods to display, and other useful stuff */

- (BOOL)acceptsFirstMouse
{
    [textObj printf:"In acceptsFirstMouse:\n"];
    return YES;
}

- (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent
{
 	// This is the other portion of the new appkit functionality
	// which allows you to drag a partially obscure object without
	// making the source window become main, and without making the
	// source application the current app.
    [textObj printf:"In shouldDelayWindowOrderingForEvent:\n"];
    return YES;
}

- sizeTo:(NXCoord)x :(NXCoord)y
{
    [textObj printf:"In sizeTo::\n"];
	
    [super sizeTo:x :y];
    [theImage setSize:&bounds.size];
    return self;	
}

- open:sender
{
    static const char *const types[] = {"tiff", "eps", NULL};
    
    [textObj printf:"In open:\n"];
	
    // get a filename to open
    if ([[OpenPanel new] runModalForTypes:types] == 0) return nil;
        
    // create an image from the file
    // it'll be whatever size the file tells it to be
	[self setImage:[[NXImage alloc] initFromFile:[[OpenPanel new] filename]]];
	
    return self;
}

- setImage:(id)anImage
{
    [textObj printf:"In setImage:\n"];

    // free theImage it if is been used
	if(theImage) [theImage free];
	
	framed = NO;
	theImage = anImage;
    [theImage setScalable:YES];		// scaleable yes
    [theImage setSize:&bounds.size];	// rescale to the same size as view
    [self display];

	return self;
}

- drawSelf:(const NXRect *)rects :(int)num
{	
	// if we are copying the PS code onto the Pboard, then we don't want
	// the white background.  Only the image.
    if (drawBackground) NXEraseRect(rects);
	
	// Composite the image into the view.
    [theImage composite:NX_SOVER toPoint:&bounds.origin];
	// if we are in the middle of a drag operation then we can frame the
	// view rect to show our acceptance of the incomming data.  Another way
	// would be to create a ghost image similar to the shelf in Workspace.
	if(framed) {
		NXFrameRectWithWidth(&bounds, (NXCoord)3.0);
	}
    return self;
}

- free
{
    [textObj printf:"In free:\n"];

	// be a good object and free things up
	[theImage free];
	return [super free];
}

@end
